1   package uba.db;
2   
3   import java.util.Collection;
4   import java.util.HashMap;
5   import java.util.List;
6   import java.util.Map;
7   
8   import junit.framework.TestCase;
9   
10  import org.apache.commons.collections.CollectionUtils;
11  import org.apache.commons.collections.TransformerUtils;
12  
13  import uba.db.column.CharColumnSpecification;
14  import uba.db.column.Column;
15  import uba.db.column.ColumnConstraint;
16  import uba.db.column.ColumnSpecification;
17  import uba.db.column.IntegerColumnSpecification;
18  import uba.db.table.Row;
19  import uba.db.table.Table;
20  import uba.db.table.TableSchema;
21  import uba.db.table.TableSchemaBuilder;
22  import uba.db.table.io.TableReader;
23  
24  /***
25   * Esta clase sirve como base para crear test de unidad de implementaciones de
26   * la base de datos (interfaz {@link Database}).
27   * 
28   * @version $Revision: 1.4 $
29   */
30  public abstract class DatabaseImplTest extends TestCase {
31      /***
32       * Nombre utilizado para la tabla "Empleado"
33       */
34      protected static final String EMPLOYEE_TABLE_NAME = "empleado";
35  
36      /***
37       * Esta variable se inicializa en el {@link #setUp()} con la implementación
38       * a testear.
39       */
40      protected Database database;
41  
42      /***
43       * Esquema de tabla utilizado para las pruebas (se inicializa en
44       * {@link #setUp()}).
45       */
46      protected TableSchema employeeSchema;
47  
48      /***
49       * @see junit.framework.TestCase#setUp()
50       */
51      protected void setUp() throws Exception {
52          super.setUp();
53          database = createDatabase();
54          employeeSchema = new TableSchemaBuilder(EMPLOYEE_TABLE_NAME)
55                  .addColumn(new IntegerColumnSpecification("eid"))
56                  .addColumn(new CharColumnSpecification("nombre", 20,
57                          ColumnConstraint.NOT_NULL))
58                  .addColumn(new IntegerColumnSpecification("salario",
59                          ColumnConstraint.NOT_NULL))
60                  .addColumn(new IntegerColumnSpecification("edad",
61                          ColumnConstraint.NOT_NULL)).addPrimaryKeyConstraintTo("eid")
62                  .build();
63      }
64  
65      /***
66       * Las sub-clases deben implementar este método para retorna la instancia
67       * concreta de {@link Database} a testear.
68       * 
69       * @throws DatabaseInitializationException
70       *             si hubo un error al crear la instancia de la base de datos.
71       */
72      protected abstract Database createDatabase() throws DatabaseInitializationException;
73  
74      /***
75       * Test: retornar las tablas del sistema.
76       */
77      public void testGetSystemTables() throws Exception {
78          assertEquals(3, database.systemTables().size());
79  
80          Table table = database.tableNamed(SystemTableSchemas.TABLES_SCHEMA.tableName());
81          assertSameSchema(table, SystemTableSchemas.TABLES_SCHEMA);
82  
83          table = database.tableNamed(SystemTableSchemas.COLUMNS_SCHEMA.tableName());
84          assertSameSchema(table, SystemTableSchemas.COLUMNS_SCHEMA);
85  
86          table = database.tableNamed(SystemTableSchemas.DATATYPES_SCHEMA.tableName());
87          assertSameSchema(table, SystemTableSchemas.DATATYPES_SCHEMA);
88      }
89  
90      /***
91       * Verifica que la tabla tenga el esquema dado.
92       * 
93       * @param table tabla
94       * @param tableSchema esquema a verificar.
95       */
96      protected void assertSameSchema(Table table, TableSchema tableSchema) {
97          int ncolumns = table.columns().size();
98          List columnSpecifications = tableSchema.columnSpecifications();
99          assertEquals(columnSpecifications.size(), ncolumns);
100         for (int i = 0; i < ncolumns; i++) {
101             ColumnSpecification colSpec = (ColumnSpecification) columnSpecifications
102                     .get(i);
103             Column col = (Column) table.columns().get(i);
104 
105             assertEquals(colSpec.name(), col.name());
106             assertEquals(colSpec.constraint(), col.constraint());
107             assertEquals(colSpec.dataTypeDisplayString(), col.dataTypeDisplayString());
108         }
109     }
110 
111     /***
112      * Test: crear una tabla.
113      */
114     public void testCreateTable() throws Exception {
115         database.createTable(employeeSchema);
116         assertEquals(1, database.userTables().size());
117 
118         Table employeeTable = (Table) database.userTables().iterator().next();
119         assertSameSchema(employeeTable, employeeSchema);
120     }
121 
122     /***
123      * Test: obtener todas las tablas (las de usuario y las del sistema).
124      */
125     public void testTables() throws Exception {
126         database.createTable(employeeSchema);
127 
128         assertEquals(4, database.tables().size());
129 
130         Collection tableNames = CollectionUtils
131                 .collect(database.tables(), TransformerUtils.invokerTransformer("name"));
132 
133         assertTrue(tableNames.contains(employeeSchema.tableName()));
134         assertTrue(tableNames.contains(SystemTableSchemas.TABLES_SCHEMA.tableName()));
135         assertTrue(tableNames.contains(SystemTableSchemas.COLUMNS_SCHEMA.tableName()));
136         assertTrue(tableNames.contains(SystemTableSchemas.DATATYPES_SCHEMA.tableName()));
137     }
138 
139     /***
140      * Test: cuando se inserta una tabla se debe actualizar el contenido de las
141      * tablas del sistema.
142      */
143     public void testUpdateSystemTablesContents() throws Exception {
144         database.createTable(employeeSchema);
145         assertEquals(4, database.tables().size());
146 
147         // verifica que la nueva tabla exista en el catalogo
148         Table tables = database.tablesTable();
149         TableReader reader = tables.reader();
150         assertTrue("el catalogo debe tener una fila con la nueva tabla", reader
151                 .hasMoreRows());
152         Row row = reader.fetchRow();
153         reader.close();
154 
155         Integer rowId = (Integer) row.valueAt(0);
156         assertEquals("la nueva tabla debe figurar en el catalogo",
157                      row.valueAt(1),
158                      employeeSchema.tableName());
159 
160         // verifica que los campos de la nueva tabla existan en el catalogo
161         Table dataTypes = database.dataTypesTable();
162         reader = dataTypes.reader();
163         Map dataTypesMap = new HashMap();
164 
165         while (reader.hasMoreRows()) {
166             row = reader.fetchRow();
167             dataTypesMap.put(row.valueAt(0), row.valueAt(1));
168         }
169         reader.close();
170 
171         Table columns = database.columnsTable();
172         reader = columns.reader();
173         Map collectedColumns = new HashMap();
174         while (reader.hasMoreRows()) {
175             row = reader.fetchRow();
176             if (row.valueAt(0).equals(rowId)) {
177                 collectedColumns.put(row.valueAt(2), dataTypesMap.get(row.valueAt(3)));
178             }
179         }
180         reader.close();
181 
182         assertTrue(collectedColumns.containsKey("eid"));
183         assertEquals(IntegerColumnSpecification.DATATYPE_DISPLAY_STRING, collectedColumns
184                 .get("eid"));
185         assertTrue(collectedColumns.containsKey("nombre"));
186         assertEquals(CharColumnSpecification.DATATYPE_DISPLAY_STRING, collectedColumns
187                 .get("nombre"));
188         assertTrue(collectedColumns.containsKey("salario"));
189         assertEquals(IntegerColumnSpecification.DATATYPE_DISPLAY_STRING, collectedColumns
190                 .get("salario"));
191         assertTrue(collectedColumns.containsKey("edad"));
192         assertEquals(IntegerColumnSpecification.DATATYPE_DISPLAY_STRING, collectedColumns
193                 .get("edad"));
194     }
195 
196     /***
197      * Test: Obtener una tabla por su nombre (el lookup debe ser case
198      * insesitve).
199      */
200     public void testTableNamed() throws Exception {
201         database.createTable(employeeSchema);
202         Table table = null;
203 
204         try {
205             table = database.tableNamed("empleado");
206         } catch (UnknowTableName e) {
207             fail("No se pudo obtener la tabla empleado, aunque existe en la base");
208         }
209 
210         assertNotNull(table);
211         assertSameSchema(table, employeeSchema);
212     }
213 }